﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using OMR.Lib.Database;
using Windows.Storage;

namespace OMR.Database.WinRT
{
    public class WinRTStorage : IStorage
    {
        private List<Type> RegisteredTypes = new List<Type>();

        private ApplicationDataContainer roamingSettings;

        public WinRTStorage(WinRTStorageTypes winRTRoamingType)
        {
            if (winRTRoamingType == WinRTStorageTypes.Local)
            {
                roamingSettings = ApplicationData.Current.LocalSettings;
            }
            else if (winRTRoamingType == WinRTStorageTypes.Roaming)
            {
                roamingSettings = ApplicationData.Current.RoamingSettings;
            }
            else
            {
                throw new NotImplementedException(); // TODO: message
            }
        }

        private string GetEntityPath(Type entityType, Guid id)
        {
            return entityType.FullName + "$" + id.ToString();
        }

        private string GetEntityPath(EntityBase entity)
        {
            return entity.GetType().FullName + "$" + entity.Id.ToString();
        }

        private static string SerializeToBase64(object obj)
        {
            var s = new XmlSerializer(obj.GetType());

            using (var ms = new MemoryStream())
            {
                using (var w = new StreamWriter(ms, Encoding.UTF8))
                {
                    s.Serialize(w, obj);
                }

                return Convert.ToBase64String(ms.ToArray());
            }
        }

        private static object DeserializeBase64String(string base64String, Type objectType)
        {
            var s = new XmlSerializer(objectType);

            byte[] data = Convert.FromBase64String(base64String);

            using (var r = new MemoryStream(data))
            {
                return s.Deserialize(r);
            }
        }

        public bool Create(EntityBase entity)
        {
            string xmlContent = SerializeToBase64(entity);

            roamingSettings.Values[GetEntityPath(entity)] = xmlContent;

            return true;
        }

        public bool Delete(EntityBase entity)
        {
            roamingSettings.Values.Remove(GetEntityPath(entity));

            return true;
        }

        public System.Collections.Generic.IEnumerable<EntityBase> GetAllEntities()
        {
            foreach (var item in roamingSettings.Values)
            {
                string typeName = item.Key.Split('$')[0];

                Type t = FindType(typeName);

                var obj = (EntityBase)DeserializeBase64String(item.Value.ToString(), t);

                yield return obj;
            }

        }

        public void RegisterTypes(params Type[] types)
        {
            foreach (Type item in types)
            {
                RegisteredTypes.Add(item);
            }
        }

        private Type FindType(string typeName)
        {
            Type t = Type.GetType(typeName);

            if (t == null)
            {
                t = RegisteredTypes.Where(f => f.FullName == typeName).FirstOrDefault();
            }

            if (t == null)
            {
                throw new Exception(typeName + " can not be found"); // TODO: message
            }

            return t;
        }

        public object Read(System.Guid id, System.Type objectType)
        {
            return roamingSettings.Values[objectType.FullName + "$" + id.ToString()]; // TODO:
        }

        public bool Update(EntityBase entity)
        {
            if (!roamingSettings.Values.ContainsKey(GetEntityPath(entity)))
                throw new Exception(); // TODO:

            roamingSettings.Values[GetEntityPath(entity)] = SerializeToBase64(entity);

            return true;
        }

    }


}
